//*** Guidance generated code ***//
using System.Linq;
using System.Collections.Generic;
using System;
using System.Reflection;
using Castle.DynamicProxy;

using $prjsn$.Aop;

using ProjectBase.Core;
using $prjsn$.Common.Business.Services;

namespace $safeprojectname$.IoC
{
    [Serializable]
    public class AopSelector : IInterceptorSelector
    {
        public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors)
        {
            IEnumerable<IInterceptor> list = interceptors;

            list = ShouldApplyBindFilter(type, method, list);
            list = ShouldApplyBindEntity(type, method, list);
            list = ShouldApplyAddOrUpdate(type, method, list);
            list = ShouldApplyTracing(type, method, list);
            list = ShouldApplyMetaDataRestriction(type, method, list);

            return list.ToArray();
        }

        private static IEnumerable<IInterceptor> ShouldApplyMetaDataRestriction(Type type, MethodInfo method, IEnumerable<IInterceptor> list)
        {
            // GetMetaData will be restricted after execution
            var isGetMetaData = method.Name.IsEqual("GetMetaData")
                                  && type.GetInterfaces().Any(i => i.IsEquivalentTo(typeof(IMetaDataProvider)));

            if (!isGetMetaData)
            {
                // Remove for any but IMetaDataProvider.GetMetaData
                list = list.Where(i => !(i is RestrictMetaDataFilter));
            }
            return list;
        }

        private static IEnumerable<IInterceptor> ShouldApplyAddOrUpdate(Type type, MethodInfo method, IEnumerable<IInterceptor> list)
        {
            // Auditing: compare before/after bind
            var isFacadeAndAddOrUpdate = (method.Name.IsEqual("Add") || method.Name.IsEqual("Update"))
                                         && type.GetInterfaces().Any(i => i.IsEquivalentTo(typeof(IFacade)));
            if (!isFacadeAndAddOrUpdate)
            {
                // Remove for any but IFacade's Add/Update operation
                list = list.Where(i => !(i is TraceableFilter));
            }
            return list;
        }

        private static IEnumerable<IInterceptor> ShouldApplyBindEntity(Type type, MethodInfo method, IEnumerable<IInterceptor> list)
        {
            // Auditing: compare before/after bind
            var isFacadeAndMethodBindEntity = method.Name.IsEqual("BindEntity")
                                              && type.GetInterfaces().Any(i => i.IsEquivalentTo(typeof(IFacade)));
            if (!isFacadeAndMethodBindEntity)
            {
                // Remove for any but IFacade's BindEntity operation
                list = list.Where(i => !(i is AuditableFilter));
            }
            return list;
        }

        private static IEnumerable<IInterceptor> ShouldApplyBindFilter(Type type, MethodInfo method, IEnumerable<IInterceptor> list)
        {
            // Filter Restriction
            var isFacadeAndMethodBindFilter = method.Name.IsEqual("BindFilter")
                                              && type.GetInterfaces().Any(i => i.IsEquivalentTo(typeof(IFacade)));

            if (!isFacadeAndMethodBindFilter)
            {
                // Remove for any but IFacade's BindFilter operation
                list = list.Where(i => !(i is FilterRestrictionManager));
            }
            return list;
        }

        private static IEnumerable<IInterceptor> ShouldApplyTracing(Type type, MethodInfo method, IEnumerable<IInterceptor> list)
        {
            // Filter Restriction
            var isTranslation = method.Name.IsEqual("GetAll")
                                && (type.GetInterfaces().Any(
                                    i => i.IsEquivalentTo(typeof(ITranslatorFacade))
                                      || i.IsEquivalentTo(typeof(ILangFacade)))
                                   );

            if (isTranslation)
            {
                // Remove trace for Translator and Language Facade GetAll()
                list = list.Where(i => !(i is TracingFilter));
            }
            return list;
        }
    }
}